package com.user.profile.service.label;

import com.alibaba.fastjson.JSON;
import com.user.profile.enums.OperateEnum;
import com.user.profile.request.SaveLabelRequest.UserData;
import com.user.profile.request.SaveLabelRequest.UserInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javafx.util.Pair;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * @Author linlx
 * @Date 2021/9/17 16:38
 * @Description
 **/
@Service
public class CommonHelper {

  @Resource
  private ThreadIndexHelper threadIndexHelper;


  public Pair<StringBuilder, Map<Integer, UserInfo>> buildAllOperate(
      UserData userData) {
    if (null == userData) {
      return null;
    }
    List<UserInfo> dataList = userData.getDataList();
    StringBuilder parentOperate = new StringBuilder();
    Map<Integer, UserInfo> infoMap = new HashMap<>();
    List<String> parentOperateList = new ArrayList<>();
    String signOperate = "";
    boolean signFlag = false;
    for (int i = 0; i < dataList.size(); i++) {
      Pair<StringBuilder, Boolean> pair = this
          .buildParentOperateAndSignFlag(parentOperate, i, userData.getOperate(),
              signFlag);
      parentOperate = pair.getKey();
      signFlag = pair.getValue();
      int index = threadIndexHelper.getLabelIndex();
      parentOperate.append("user").append(index);
      signOperate = this
          .buildParentOperateAndGetSignOperate(parentOperate, signOperate, signFlag, i);
      infoMap.put(index, dataList.get(i));
      // 两两凑成一组才统计
      if ((i + 1) % 2 == 0) {
        parentOperateList.add(parentOperate.toString());
        continue;
      }
      // % 2 等于1的情况 并且为最后一个
      if (i == dataList.size() - 1) {
        signOperate = parentOperate.toString();
      }
    }
    System.out.println(JSON.toJSONString(parentOperateList));
    System.out.println(JSON.toJSONString(infoMap));

    // 由于bitmap函数只支持两个入参做交并差，所以这里递归去两两组合条件
    List<String> listResult = this
        .buildParentOperateRecursion(parentOperateList, userData);

    // 拼接父标签的bitmap条件
    StringBuilder operateBuilder = this.buildParentOperate(signOperate, signFlag, listResult,
        dataList.size(), userData.getOperate());
    // 特殊处理父标签为奇数并且不是单标签的情况
    if (!StringUtils.isEmpty(signOperate) && !signFlag) {
      operateBuilder.append(")");
    }

    System.out.println("-----------------" + operateBuilder.toString());

    // 处理子关系 start
    Set<Entry<Integer, UserInfo>> entries = infoMap.entrySet();
    // 所有的标签
    Map<Integer, UserInfo> allMap = new HashMap<>(infoMap);
    for (Entry<Integer, UserInfo> entry : entries) {
      StringBuilder resultString = new StringBuilder();
      UserInfo value = entry.getValue();
      List<UserInfo> sonList = value.getDataList();
      if (CollectionUtils.isEmpty(sonList)) {
        continue;
      }
      // 只有单个子标签，则直接和上级标签拼接成bitmap
      if (sonList.size() == 1) {
        int index = threadIndexHelper.getLabelIndex();
        operateBuilder = this.buildSignLabel(operateBuilder, resultString, index,
            value.getSonOperate());
        allMap.put(index, sonList.get(0));
        continue;
      }
      // 先把所有子集条件完成两两组合,逻辑同父标签
      String sonSign = StringUtils.EMPTY;
      List<String> sonLabelList = new ArrayList<>();
      StringBuilder sonBuffer = new StringBuilder();
      for (int i = 0; i < sonList.size(); i++) {
        int index = threadIndexHelper.getLabelIndex();
        allMap.put(index, sonList.get(i));
        sonBuffer = this.getSonBuffer(sonBuffer, i, value.getSonOperate(), index);
        if ((i + 1) % 2 == 0) {
          sonLabelList.add(sonBuffer.toString());
          continue;
        }
        if (i == sonList.size() - 1) {
          sonSign = sonBuffer.toString();
        }
      }
      // 由于bitmap函数只支持两个入参做交并差，所以这里递归去两两组合条件
      List<String> resultSonList = this.buildSonOperateRecursion(sonLabelList, value);

      // 拼接主子的关系
      if (OperateEnum.AND.getCode().equals(value.getSonOperate())) {
        resultString.append("bitmapAnd(");
      } else if (OperateEnum.OR.getCode().equals(value.getSonOperate())) {
        resultString.append("bitmapOr(");
      }

      // 3 4 8
      if (resultSonList.size() > 1) {
        resultString.append("user").append(entry.getKey()).append(",");
        // 4 8
        this.buildResultString(resultString, sonSign, resultSonList, sonList.size(),
            value.getSonOperate());
      } else {
        // 1 2
        if (sonList.size() % 2 == 0) {
          // 2
          resultString.append("user").append(entry.getKey()).append(",")
              .append(resultSonList.get(0))
              .append(")");
        } else {
          // 1 这里不会走 因为子集单标签在上面已经处理过了
          resultString.append("user").append(entry.getKey()).append(",")
              .append(sonSign)
              .append(resultSonList.get(0))
              .append(")")
              .append(")");
        }
      }
      operateBuilder = new StringBuilder(
          operateBuilder.toString().replace("user" + entry.getKey(), resultString.toString()));
    }
    System.out.println(operateBuilder.toString());
    System.out.println(JSON.toJSONString(allMap));
    // 处理子关系 end
    return new Pair<>(operateBuilder, allMap);
  }

  private void buildResultString(StringBuilder resultString, String sonSign,
      List<String> resultSonList,
      int size, Integer sonOperate) {
    if (size % 2 == 0) {
      if (OperateEnum.AND.getCode().equals(sonOperate)) {
        resultString.append("bitmapAnd(");
      } else if (OperateEnum.OR.getCode().equals(sonOperate)) {
        resultString.append("bitmapOr(");
      }
      resultString.append(resultSonList.get(0)).append(",").append(resultSonList.get(1))
          .append(")")
          .append(")");
    } else {
      // 3
      resultString.append(sonSign);
      if (OperateEnum.AND.getCode().equals(sonOperate)) {
        resultString.append("bitmapAnd(");
      } else if (OperateEnum.OR.getCode().equals(sonOperate)) {
        resultString.append("bitmapOr(");
      }
      resultString.append(resultSonList.get(0)).append(",").append(resultSonList.get(1))
          .append(")")
          .append(")")
          .append(")");
    }
  }

  private StringBuilder getSonBuffer(StringBuilder sonBuffer, int i, Integer sonOperate,
      int index) {
    if (i == 0 || i % 2 == 0) {
      sonBuffer = new StringBuilder();
      if (OperateEnum.AND.getCode().equals(sonOperate)) {
        sonBuffer.append("bitmapAnd(");
      } else if (OperateEnum.OR.getCode().equals(sonOperate)) {
        sonBuffer.append("bitmapOr(");
      }
    }
    sonBuffer.append("user").append(index);
    if ((i + 1) % 2 == 0) {
      sonBuffer.append(")");
    } else {
      sonBuffer.append(",");
    }
    return sonBuffer;
  }

  private StringBuilder buildSignLabel(StringBuilder operateBuilder, StringBuilder resultString,
      int index, Integer sonOperate) {
    if (OperateEnum.AND.getCode().equals(sonOperate)) {
      resultString.append("bitmapAnd(");
    } else if (OperateEnum.OR.getCode().equals(sonOperate)) {
      resultString.append("bitmapOr(");
    }
    resultString.append(operateBuilder).append(",").append("user").append(index).append(")");
    return resultString;
  }

  private StringBuilder buildParentOperate(String signOperate, boolean signFlag,
      List<String> listResult, int size, Integer operate) {
    StringBuilder parentOperateBuilder = new StringBuilder();
    if (listResult.size() > 1) {
      if (size % 2 == 0 && !StringUtils.isEmpty(signOperate)) {
        if (OperateEnum.AND.getCode().equals(operate)) {
          parentOperateBuilder.append("bitmapAnd(");
        } else if (OperateEnum.OR.getCode().equals(operate)) {
          parentOperateBuilder.append("bitmapOr(");
        }
      } else {
        if (OperateEnum.AND.getCode().equals(operate)) {
          parentOperateBuilder.append("bitmapAnd(");
        } else if (OperateEnum.OR.getCode().equals(operate)) {
          parentOperateBuilder.append("bitmapOr(");
        }
      }
      parentOperateBuilder.append(listResult.get(0)).append(",").append(listResult.get(1))
          .append(")");
    } else {
      if (signFlag) {
        parentOperateBuilder = new StringBuilder(signOperate);
      } else {
        parentOperateBuilder.append(signOperate).append(listResult.get(0));
      }
    }
    return parentOperateBuilder;
  }

  private String buildParentOperateAndGetSignOperate(StringBuilder parentOperate,
      String signOperate, boolean signFlag,
      int i) {
    if (!signFlag) {
      if ((i + 1) % 2 == 0) {
        parentOperate.append(")");
      } else {
        parentOperate.append(",");
      }
    } else {
      signOperate = parentOperate.toString();
    }
    return signOperate;
  }

  private List<String> buildParentOperateRecursion(List<String> parentOperateList,
      UserData userAttributesData) {
    StringBuilder operateBuilder = new StringBuilder();
    if (parentOperateList.size() > 2) {
      this.dealGtTwo(parentOperateList, operateBuilder, userAttributesData.getOperate());
      this.buildParentOperateRecursion(parentOperateList, userAttributesData);
    }
    return parentOperateList;
  }

  private List<String> buildSonOperateRecursion(List<String> list,
      UserInfo userAttributesInfo) {
    StringBuilder operateBuilder = new StringBuilder();
    if (list.size() > 2) {
      this.dealGtTwo(list, operateBuilder, userAttributesInfo.getSonOperate());
      this.buildSonOperateRecursion(list, userAttributesInfo);
    }
    return list;
  }


  @SuppressWarnings("deprecation")
  private void dealGtTwo(List<String> list, StringBuilder operateBuilder, Integer operate) {
    if (OperateEnum.AND.getCode().equals(operate)) {
      operateBuilder.append("bitmapAnd(");
    } else if (OperateEnum.OR.getCode().equals(operate)) {
      operateBuilder.append("bitmapOr(");
    }
    operateBuilder.append(list.get(0)).append(",").append(list.get(1)).append(")");
    list.remove(1);
    list.remove(0);
    list.add(operateBuilder.toString());
  }

  private Pair<StringBuilder, Boolean> buildParentOperateAndSignFlag(StringBuilder parentOperate,
      int i,
      Integer operate,
      boolean signFlag) {
    if (i == 0 || i % 2 == 0) {
      parentOperate = new StringBuilder();
      if (OperateEnum.AND.getCode().equals(operate)) {
        parentOperate.append("bitmapAnd(");
      } else if (OperateEnum.OR.getCode().equals(operate)) {
        parentOperate.append("bitmapOr(");
      } else if (null == operate) {
        // 单标签
        signFlag = true;
      }
    }
    return new Pair<>(parentOperate, signFlag);
  }
}
